C++11起，可以让调用者决定函数模板参数是通过值传递，还是通过引用传递。当模板声明为按值接受参数时，调用者可以使用在头文件<functional>中声明的std::cref()和std::ref()，通过引用传递参数。例如:

\begin{lstlisting}[style=styleCXX]
template<typename T>
void printT (T arg) {
	...
}

std::string s = "hello";
printT(s); // pass s by value
printT(std::cref(s)); // pass s “as if by reference”
\end{lstlisting}

注意std::cref()不会改变模板中参数的处理，之类使用了一个技巧:用一个引用的对象来包装传递的参数。事实上，这会创建了一个std::reference\_wrapper<>类型的对象，引用原始参数，并按值传递了这个对象。包装器或多或少支持一种操作:返回原始类型的隐式类型转换，生成原始对象。

\begin{tcolorbox}[colback=webgreen!5!white,colframe=webgreen!75!black]
\hspace*{0.75cm}还可以在引用包装器上调用get()并将其用作函数对象。
\end{tcolorbox}

因此，只要对传递的对象有有效的操作符，就可以使用引用包装器。例如:

\hspace*{\fill} \\ %插入空行
\noindent
\textit{basics/cref.cpp}
\begin{lstlisting}[style=styleCXX]
#include <functional> // for std::cref()
#include <string>
#include <iostream>

void printString(std::string const& s)
{
	std::cout << s << ’\n’;
}

template<typename T>
void printT (T arg)
{
	printString(arg); // might convert arg back to std::string
}

int main()
{
	std::string s = "hello";
	printT(s); // print s passed by value
	printT(std::cref(s)); // print s passed “as if by reference”
}
\end{lstlisting}

最后一次调用通过值传递std::reference\_wrapper<string const>类型的对象到参数arg，然后传递并转换回其底层类型std::string。

编译器必须知道返回原始类型必要的隐式转换。因此，只有通过泛型代码将对象传递给非泛型函数时，std::ref()和std::cref()才能正常工作。例如，因为没有为std::reference\_wrapper<>定义输出操作符，直接尝试输出传递的泛型类型T对象将失败:

\begin{lstlisting}[style=styleCXX]
template<typename T>
void printV (T arg) {
	std::cout << arg << ’\n’;
}
...
std::string s = "hello";
printV(s); // OK
printV(std::cref(s)); // ERROR: no operator << for reference wrapper defined
\end{lstlisting}

此外，因为不能比较一个引用包装与char const*或std::string，所以会失败:

\begin{lstlisting}[style=styleCXX]
template<typename T1, typename T2>
bool isless(T1 arg1, T2 arg2)
{
	return arg1 < arg2;
}
...
std::string s = "hello";
if (isless(std::cref(s), "world")) ... // ERROR
if (isless(std::cref(s), std::string("world"))) ... // ERROR
\end{lstlisting}

将arg1和arg2声明为通用类型T也没有帮助:

\begin{lstlisting}[style=styleCXX]
template<typename T>
bool isless(T arg1, T arg2)
{
	return arg1 < arg2;
}
\end{lstlisting}

因为当编译器试图为arg1和arg2推导T时，类型会冲突。

因此，类std::reference\_wrapper<>的作用是将引用用作“第一个类对象”，可以复制，并通过值传递给函数模板。也可以在类中使用它，例如：保存容器中对象的引用。但是最终需要转换回基础类型。











